﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ApplicationServer.Caching;
using CYTS.Aoyou.Framework.Log;

namespace CYTS.Aoyou.Framework.Cache
{
    /// <summary>
    /// AppFabric帮助类
    /// </summary>
    public class AppFabricHelper
    {
        private static DataCacheFactory dataCacheFactory = null;
        private static DataCacheFactoryConfiguration configuration = null;
        private static Dictionary<string, DataCache> dicDataCache = new Dictionary<string, DataCache>();
        private static object lockObj = new object();

        private DataCache dataCache = null;

        public AppFabricHelper(string[] hosts, string cacheName = "TemporaryData")
        {
            lock (lockObj)
            {
                string key = cacheName;
                if (configuration == null || dataCacheFactory == null || !AreEqual(hosts, configuration.Servers))
                {
                    CreateDataCache(hosts, cacheName);
                    dicDataCache[key] = dataCache;
                }
                else
                {
                    if (!dicDataCache.TryGetValue(key, out dataCache))
                    {
                        dataCache = dataCacheFactory.GetCache(cacheName);
                        dicDataCache[key] = dataCache;
                    }
                }
            }
        }

        /// <summary>
        /// 清除内存中缓存的DataCache
        /// </summary>
        public static void RemoveAllDataCacheInMemory()
        {
            lock (lockObj)
            {
                dicDataCache.Clear();
            }
        }

        /// <summary>
        /// 获取内存中缓存的DataCache
        /// </summary>
        /// <returns></returns>
        public static IList<DataCache> GetAllDataCacheListInMemory()
        {
            return dicDataCache.Values.ToList();
        }

        /// <summary>
        /// 创建Region
        /// </summary>
        /// <param name="regionName">区域名</param>
        public void CreateRegion(string regionName)
        {
            try
            {
                dataCache.CreateRegion(regionName);
            }
            catch(Exception ex)
            {
                string msg = "创建Region失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 删除Region
        /// </summary>
        /// <param name="regionName">区域名</param>
        public void DeleteRegion(string regionName)
        {
            try
            {
                dataCache.RemoveRegion(regionName);
            }
            catch (Exception ex)
            {
                string msg = "删除Region失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 设置服务器上存储数据。
        /// </summary>
        /// <param name="key">KEY</param>
        /// <param name="value">Value</param>
        public void Put(string key, object value)
        {
            try
            {
                dataCache.Put(key, value);
            }
            catch (Exception ex)
            {
                string msg = "设置服务器上的存储数据失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 设置覆其上存储的数据，分区域
        /// </summary>
        /// <param name="key">KEY</param>
        /// <param name="value">Value</param>
        /// <param name="region">区域名称</param>
        public void Put(string key, object value, string region)
        {
            try
            {
                dataCache.Put(key, value, region);
            }
            catch (Exception ex)
            {
                string msg = "设置服务器上的存储数据失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 在服务器上存储数据，并指定过期时间
        /// </summary>
        /// <param name="key">KEY</param>
        /// <param name="value">Value</param>
        /// <param name="expiry">时间间隔</param>
        /// <returns>是否成功</returns>
        public void Put(string key, object value, TimeSpan expiry)
        {
            try
            {
                dataCache.Put(key, value, expiry);
            }
            catch (Exception ex)
            {
                string msg = "设置服务器上的存储数据失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 在服务器上存储数据，并指定过期时间（制定区域）
        /// </summary>
        /// <param name="key">KEY</param>
        /// <param name="value">Value</param>
        /// <param name="region">区域</param>
        /// <param name="expiry">过期间隔</param>
        public void Put(string key, object value, string region, TimeSpan expiry)
        {
            try
            {
                dataCache.Put(key, value, expiry, region);
            }
            catch (Exception ex)
            {
                string msg = "设置服务器上的存储数据失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 从缓存中删除key.
        /// </summary>
        /// <param name="key">缓存项KEY</param>
        public void Delete(string key)
        {
            try
            {
                dataCache.Remove(key);
            }
            catch (Exception ex)
            {
                string msg = "从缓存中删除key失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 从缓存中删除key.
        /// </summary>
        /// <param name="key">缓存项KEY</param>
        /// <param name="region">区域</param>
        public void Delete(string key, string region)
        {
            try
            {
                dataCache.Remove(key, region);
            }
            catch (Exception ex)
            {
                string msg = "从缓存中删除key失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 向缓存中添加key
        /// </summary>
        /// <param name="key">缓存项KEY</param>
        /// <param name="value">缓存项值</param>
        public void Add(string key, object value)
        {
            try
            {
                dataCache.Add(key, value);
            }
            catch (Exception ex)
            {
                string msg = "从缓存中添加key失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 向缓存中添加key(指定区域)
        /// </summary>
        /// <param name="key">缓存项KEY</param>
        /// <param name="value">缓存项值</param>
        /// <param name="region">区域</param>
        public void Add(string key, object value, string region)
        {
            try
            {
                dataCache.Add(key, value, region);
            }
            catch (Exception ex)
            {
                string msg = "从缓存中添加key失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 向缓存中添加key,并指定过期时间
        /// </summary>
        /// <param name="key">缓存项KEY</param>
        /// <param name="value">缓存项值</param>
        /// <param name="expiry">过期时间</param>
        public void Add(string key, object value, TimeSpan expiry)
        {
            try
            {
                dataCache.Add(key, value, expiry);
            }
            catch (Exception ex)
            {
                string msg = "从缓存中添加key失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 向缓存中添加key,并指定过期时间
        /// </summary>
        /// <param name="key">缓存项KEY</param>
        /// <param name="value">缓存项值</param>
        /// <param name="expiry">时间间隔</param>
        /// <param name="region">缓存区域</param>
        public void Add(string key, object value, TimeSpan expiry, string region)
        {
            try
            {
                dataCache.Add(key, value, expiry, region);
            }
            catch (Exception ex)
            {
                string msg = "从缓存中添加key失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// key是否存在
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns>是否存在</returns>
        public bool KeyExists(string key)
        {
            try
            {
                if (dataCache.Get(key) == null)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                string msg = "判断key是否存在时出错";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// key是否存在
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="region">缓存区域</param>
        /// <returns>是否存在</returns>
        public bool KeyExists(string key, string region)
        {
            try
            {
                if (dataCache.Get(key, region) == null)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                string msg = "判断key是否存在时出错";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 根据key值，获取缓存数据
        /// </summary>
        /// <param name="key">缓存KEY</param>
        /// <param name="region">缓存区域</param>
        /// <returns>缓存值</returns>
        public object Get(string key, string region)
        {
            try
            {
                return dataCache.Get(key, region);
            }
            catch (Exception ex)
            {
                string msg = "根据key值获取缓存数据时出错";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 根据key值，获取缓存数据
        /// </summary>
        /// <param name="key">缓存KEY</param>
        /// <returns>缓存值</returns>
        public object Get(string key)
        {
            try
            {
                return dataCache.Get(key);
            }
            catch (Exception ex)
            {
                string msg = "根据key值获取缓存数据时出错";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        /// <summary>
        /// 获得多个key值
        /// </summary>
        /// <param name="keys">Key数组</param>
        /// <returns>缓存对象</returns>
        public object[] GetMultipleArray(string[] keys)
        {
            int count = keys.Count();
            object[] result = new object[count];
            try
            {
                for (int i = 0; i < keys.Count(); i++)
                {
                    result[i] = dataCache.Get(keys[i]);
                }
                return result;
            }
            catch (Exception ex)
            {
                string msg = "根据多个key值获取缓存数据时出错";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }


        private void CreateDataCache(string[] hosts, string cacheName)
        {
            try
            {
                List<DataCacheServerEndpoint> servers = new List<DataCacheServerEndpoint>();
                foreach (var host in hosts)
                {
                    string[] splitedHost = host.Split(':');
                    servers.Add(new DataCacheServerEndpoint(splitedHost[0], Convert.ToInt32(splitedHost[1])));
                }

                configuration = new DataCacheFactoryConfiguration();
                configuration.Servers = servers;

                DataCacheSecurity dataCacheSecurity = new DataCacheSecurity(DataCacheSecurityMode.None, DataCacheProtectionLevel.None);
                configuration.SecurityProperties = dataCacheSecurity;

                configuration.LocalCacheProperties = new DataCacheLocalCacheProperties();
                DataCacheClientLogManager.ChangeLogLevel(System.Diagnostics.TraceLevel.Off);
                Action function = () => { dataCacheFactory = new DataCacheFactory(configuration); };
                IAsyncResult result = function.BeginInvoke(null, function);
                if (!result.AsyncWaitHandle.WaitOne(1000 * 5))
                {
                    throw new Exception("AppFabric缓存连接不可用");
                }
                dataCache = dataCacheFactory.GetCache(cacheName);
            }
            catch (Exception ex)
            {
                string msg = "创建AppFabric连接失败";
                //Logger.LogError(msg, ex);
                throw new Exception(msg, ex);
            }
        }

        private bool AreEqual(string[] hosts, IEnumerable<DataCacheServerEndpoint> endpoints)
        {
            string[] arrayEndpoint = endpoints.Select(p => p.HostName + ":" + p.CachePort).ToArray();
            return hosts != null && arrayEndpoint != null && hosts.Length > 0
                && hosts.Length == arrayEndpoint.Length && hosts.Intersect(arrayEndpoint).Count() == hosts.Length;
        }
    }
}
